import json
import os
import time


from apilib.component import compManager,TComp

class TCompClock(TComp):
    def __init__(self):
        super().__init__()
        self.eventHandlers ={
            "timeTicker": None ,
            "threshold": None ,
            "marker": None ,
            "clockAction": None
        }
        self.handlers={
            "acClockAction", self.acClockAction ,
            "acSetMarker", self.acSetMarker ,
            "acSetClockTime", self.acSetClockTime,
            "acGetStatus", self.acGetStatus
        }
        self.autoStartServices={}
        self.reverseFlag = False
        # 授时机构 0-外部装置授时；1-系统自授时；
        self.timeSrc = 1
        self.thresholds ={}
        self.executeHnadler = None
        self.executeInterval = 0.1

        self.nowTime = 0
        self.startTime=0
        self.endTime = 0
        self.pauseLog =[]
        self.markers= []
        self.actionLog =[]

        self.status= {
            "enable_acStart": False,
            "enable_acPause": False,
            "enable_acResume": False,
            "enable_acEnd": False,

            "thresholdStatus":{},
            "markers":[],
            "isRunning": False ,
            "isPause": False,
            "pauseNums": 0 ,
            "totalTime": 0 ,
            "pauseTime": 0 ,
            "netTime": 0 ,
            "startTime": 0 ,
            "endTime": 0 ,
            "nowTime": 0 ,
            "svrTime": 0,
            "timeSrc": self.timeSrc
        }
    def compInit(self):
        try:
            for thresholdKey in self.compSettings['thresholds'].keys:
                thresholdItem = self.compSettings['thresholds'][thresholdKey]
                self.thresholds[thresholdKey] = {
                    "code": thresholdItem['code'] ,
                    "value": thresholdItem['value'] ,
                    "timeout":0 ,
                    "netTime":0 ,
                    "trigger": False
                }
            self.executeInterval = self.compSettings['executeInterval']
        except Exception as er:
            self.manager.log(er)
    def getDatatFn(self):
        res = ""
        try:
            dirPath = (self.compSettings['dataPath']).replace("{rootPath}" , self.manager.rootPath)
            if not os.path.exists(dirPath):
                os.makedirs(dirPath , 0x777)
            res = f"{dirPath}/clock_{self.code}.json"
        except Exception as er:
            self.manager.log(er)
        return res
    def getLogFn(self):
        res = ""
        try:
            dirPath = (self.compSettings['dataPath']).replace("{rootPath}" , self.manager.rootPath)
            logPath = f"{dirPath}/clockLogs/{self.code}"
            if not os.path.exists(logPath):
                os.makedirs(logPath , 0x777)
            res = f"{logPath}/log_{int(time.time())}.json"
        except Exception as er:
            self.manager.log(er)
        return res
    def saveLog(self):
        try:
            fn = self.getDatatFn()
            with open( fn , 'w' ,encoding='utf-8') as f:
                content = json.dumps(self.actionLog, ensure_ascii=False)
                f.write(content)
                f.flush()
                self.actionLog.clear()
        except Exception as er:
            self.manager.log(er)
    def updateStatus(self):
        try:
            nowTm = self.nowTime if self.timeSrc==0 else time.time()
            endTime = nowTm if self.endTime == 0 else self.endTime
            totalTime = 0 if self.startTime==0 else (endTime - self.startTime)
            pauseTime = 0 if self.startTime==0 else sum(
                [ ( nowTm if  x['end']==0 else x['end'] ) - x['startTime'] for x in self.pauseLog]
            )
            netTime = 0 if totalTime==0 else (totalTime - pauseTime)
            self.status = {
                "enable_acStart": self.startTime == 0 and self.endTime == 0 ,
                "enable_acPause": self.startTime>0 and self.endTime == 0 and len([x for x in self.pauseLog if x['end']==0])==0,
                "enable_acResume": self.startTime>0 and self.endTime == 0 and len([x for x in self.pauseLog if x['end']==0])>0,
                "enable_acEnd": self.startTime>0 and self.endTime == 0,

                "thresholdStatus":self.thresholds,
                "markers":self.markers,
                "acitved": self.startTime>0 and self.endTime==0 ,
                "isPause": len([x for x in self.pauseLog if x['end']==0])>0,
                "pauseNums": len([x for x in self.pauseLog ])>0 ,
                "totalTime": totalTime ,
                "pauseTime": pauseTime ,
                "netTime": netTime ,
                "startTime" : self.startTime,
                "endTime" : self.endTime,
                "nowTime" : nowTm,
                "svrTime": time.time(),
                "timeSrc": self.timeSrc
            }
        except Exception as er:
            self.manager.log(er)
        return  self.status
    def resetClock(self):
        try:
            self.startTime = 0
            self.endTime = 0
            self.pauseLog = []
            self.markers = []
            self.actionLog = []
        except Exception as er:
            self.manager.log(er)
    def getNetTime(self):
        res = 0
        try:
            if self.startTime>0 :
                nowTime = self.nowTime if self.timeSrc == 0 else time.time()
                pauseTime = sum([ (nowTime if x['end']==0 else x['end']) - x['start']  for x in self.pauseLog])
                endTime = nowTime if  self.endTime==0 else self.endTime
                res = endTime - self.startTime - pauseTime
        except Exception as er:
            self.manager.log(er)
        return res
    def getTimeoutList(self , includeTriggered = False):
        res = []
        netTime = 0
        try:
            if self.startTime>0 :
                netTime = self.getNetTime()
                res = [
                    x
                    for x in list(self.thresholds.values())
                    if netTime >= x['value']
                ]
                if not includeTriggered:
                    res = [x for x in res if not x['trigger']]
        except Exception as er:
            self.manager.log(er)
        return res , netTime
    def acSetClockTime(self , clockTime):
        try:
            self.nowTime = clockTime
        except Exception as er:
            self.manager.log(er)
    def acSetMarker(self , markerCode , markerType , acTime=0 , markerTag={}):
        try:
            marker = {
                "code": markerCode ,
                "type": markerType ,
                "tm": acTime if acTime>0 else self.nowTime ,
                "tag": markerTag
            }
            self.markers.append(marker)
            self.updateStatus()
            if not self.eventHandlers['marker']==None:
                try:
                    self.eventHandlers['marker'](marker)
                except Exception as erEvent :
                    self.manager.log(erEvent)
        except Exception as er:
            self.manager.log(er)
    def acClockAction(self , actionCode , acTime=0):
        try:
            tm = self.nowTime if acTime<=0  else acTime
            tm = acTime
            triggerFlag = False
            if acTime<=0 :
                if self.timeSrc==0 :
                    tm = self.nowTime
                else:
                    tm = time.time()
            if actionCode == 'acReset':
                self.resetClock()
                triggerFlag = True
            elif actionCode =='acStart':
                if self.startTime==0 :
                    self.endTime = 0
                    self.startTime = tm
                    self.executeHnadler()
                    triggerFlag = True
            elif actionCode =='acPause':
                if self.startTime>0 and self.endTime==0 :
                    pauseNums = len([p for p in self.pauseLog if p['end']==0])
                    if pauseNums==0:
                        self.pauseLog.append({
                            "start": tm ,
                            "end":0
                        })
                        triggerFlag = True
            elif actionCode =='acResume':
                if self.startTime>0 and self.endTime==0  and len(self.pauseLog)>0 and self.pauseLog[-1]['end']==0:
                    self.pauseLog[-1]['end']= tm
                    triggerFlag = True
            elif actionCode =='acEnd':
                if self.startTime > 0 and self.endTime == 0:
                    if len(self.pauseLog)>0 and self.pauseLog[-1]['end']==0:
                        self.pauseLog[-1]['end']= tm
                    self.endTime = tm
                    triggerFlag = True
            self.updateStatus()
            self.setActionLog(actionCode, acTime , {})
            if triggerFlag and not self.eventHandlers['clockAction']==None:
                try:
                    self.eventHandlers['clockAction']( actionCode , tm)
                except Exception as erEvent :
                    self.manager.log(erEvent)


        except Exception as er:
            self.manager.log(er)
    def acGetStatus(self , updateFlag= 0):
        return  self.status if updateFlag==0 else self.updateStatus()
    def setActionLog(self ,acCode , acTime=0 , acTag={}):
        try:
            log = {
                "acCode": acCode ,
                "tm": acTime if acTime>0 else self.nowTime ,
                "tag": acTag
            }
            self.actionLog.append(log)
        except Exception as er:
            self.manager.log(er)
    async def loopExecute(self):
        try:
            active =  self.startTime > 0 and self.endTime == 0 and self.executeInterval>0
            lastTm = time.time()
            while  active:
                try:
                    time.sleep(0.01)
                    if self.executeInterval>0  :
                        flag = time.time() - lastTm >= self.executeInterval
                        if flag:
                            if self.eventHandlers['timeTicker']!=None:
                                try:
                                    self.eventHandlers['timeTicker'](  )
                                except Exception as erTrigger:
                                    self.manager.log(erTrigger)
                            if self.eventHandlers['threshold'] != None:
                                untriggerThresholds , netTime = self.getTimeoutList(False)
                                for threshold in untriggerThresholds:
                                    try:
                                        threshold['netTime']= netTime
                                        threshold['trigger']= True
                                        self.updateStatus()
                                        self.eventHandlers['threshold']( threshold )
                                    except Exception as erTrigger:
                                        self.manager.log(erTrigger)
                except Exception as eer:
                    self.manager.log(eer)
                finally:
                    active = self.startTime > 0 and self.endTime == 0
        except Exception as er:
            self.manager.log(er)

_settings = {
    "dataPath":"",
    "thresholds":{},
    "executeInterval":{}
}
compManager.registComponentType('TCompClock' , TCompClock , _settings)